﻿using System;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.ServiceLocation;

namespace UltimateNavigationFramework.UriNavigation
{
    public class UltimateNavigationFrameContent : ContentControl
    {
        #region Weak Loaded Event
        private WeakReference _loadedNotifierEvent;
        public Action LoadNotifierEvent
        {
            get { return _loadedNotifierEvent != null ? _loadedNotifierEvent.Target as Action : null; }
            set
            {
                this._loadedNotifierEvent = new WeakReference(value);
            }
        } 
        #endregion

        #region IsLoaded
        public bool IsLoaded { get; private set; } 
        #endregion

        #region Constructor
        public UltimateNavigationFrameContent()
        {
            this.HorizontalContentAlignment = HorizontalAlignment.Stretch;
            this.VerticalContentAlignment = VerticalAlignment.Stretch;
            this.Loaded += UltimateNavigationFrameContentLoaded;
            this.Unloaded += UltimateNavigationFrameContentUnloaded;
        }

        private void UltimateNavigationFrameContentUnloaded(object sender, RoutedEventArgs e)
        {
            this.IsLoaded = false;
        }

        private void UltimateNavigationFrameContentLoaded(object sender, RoutedEventArgs e)
        {
            if (this.LoadNotifierEvent != null)            
                this.LoadNotifierEvent();            

            this.IsLoaded = true;            
        } 
        #endregion

        #region Properties
        public string Title { get; set; }

        private Object View
        {
            get
            {
                var contentControl = this.Content as ContentControl;

                if (contentControl != null)
                {
                    return contentControl.Content;
                }
                else
                {
                    return this.Content;
                }
            }
        }  
        #endregion        

        #region Navigation Events
        internal void InternalOnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e, Action<bool> continuationCallback)
        {
            IConfirmNavigationRequest confirmNavigation = GetT<IConfirmNavigationRequest>();
            if (confirmNavigation != null)
            {
                confirmNavigation.ConfirmNavigationRequest(
                    this.CreateNavigationContext(e.Uri),
                    r =>
                    {
                        if (continuationCallback != null)
                        {
                            continuationCallback(r);
                            continuationCallback = null;
                        }   
                    });                
            }
            else
            {
                if (continuationCallback != null)
                {
                    continuationCallback(false);
                    continuationCallback = null;
                }
            }
        }

        internal void InternalOnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs navigationEventArgs)
        {
            this.Execute<INavigationAware>(ina => { ina.OnNavigatedFrom(this.CreateNavigationContext(navigationEventArgs.Uri)); });
        }

        internal void InternalOnNavigatedTo(System.Windows.Navigation.NavigationEventArgs navigationEventArgs)
        {
            this.Execute<INavigationAware>(ina => { ina.OnNavigatedTo(this.CreateNavigationContext(navigationEventArgs.Uri)); });
        } 
        #endregion

        #region Private Methods
        NavigationContext CreateNavigationContext(Uri uri)
        {
            var service = ServiceLocator.Current.GetInstance<IRegionNavigationService>();
            var context = new NavigationContext(
                service,
                uri);            
            return context;
        }

        /// <summary>
        /// Execute Delegated Action
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        private void Execute<T>(Action<T> action) where T : class
        {
            T viewOrViewModel = GetT<T>();
            if (viewOrViewModel != null)
            {
                action(viewOrViewModel);
            }            
        }

        private T GetT<T>() where T : class
        {
            var viewAsT = this.View as T;

            if (viewAsT != null)
            {
                return viewAsT;
            }

            var viewAsFrameworkElement = this.View as FrameworkElement;
            if (viewAsFrameworkElement != null)
            {
                var dataContext = viewAsFrameworkElement.DataContext as T;

                if (dataContext != null)
                {
                    return dataContext;
                }
            }

            return default(T);
        }
        #endregion
    }
}
